<template>
  <div class="bw-node-attr-const-value">
    <template v-if="valueFrom === BwCustomComNodeAttrFromTypeEnum.constValue">
      <component
        :is="curConstEle"
        v-bind="curConstEleBindProps"
        v-on="curConstEleEmits"
      />
    </template>

    <template v-else-if="valueFrom === BwCustomComNodeAttrFromTypeEnum.comVar">
      <a-input
        class="input"
        v-model:value="curComVarName"
        @change="onChangeAttrValue(curComVarName)"
      />
    </template>

    <template
      v-else-if="valueFrom === BwCustomComNodeAttrFromTypeEnum.comProps"
    >
      <a-select
        class="input"
        style="width: 100%"
        :options="curCurtomComPropList"
        v-model:value="curComParamName"
        @change="onChangeAttrValue(curComParamName)"
      />
    </template>

    <template
      v-else-if="valueFrom === BwCustomComNodeAttrFromTypeEnum.JSExpression"
    >
      <a-button :block="true" type="primary" @click="curVisible = true">
        表达式定义
      </a-button>
    </template>

    <BwJSExtend
      v-model:visible="curVisible"
      :value="curJSExpression"
      @ok="onChangeJSExpression"
    />
  </div>
</template>

<script lang="ts">
import { useComDesignStoreWithOut } from '@/store'
import { BwNodeAttrConstValueProps, type BwCurNodeAttrInfoModel } from './props'
import {
  ref,
  unref,
  computed,
  markRaw,
  watch,
  nextTick,
  defineComponent,
} from 'vue'

import {
  BwCustomComPropDataTypeEnum,
  BwComPropSetConstValueComEnum,
  BwCustomComNodeAttrFromTypeEnum,
  BwCustomComNodeAttrDataTypeEnum,
  type BwCustomComNodeAttrModel,
} from '@bitwit/base-com-render'
import type { BwJsExtndInfoModel } from '../../../../../../coms/JSExtend/model'

import BwColSpan from './const/colSpan/index.vue'
import BwJSExtend from '../../../../../../coms/JSExtend/index.vue'
export default defineComponent({
  name: 'BwBaseComConstAttr',
  components: { BwJSExtend },
  props: BwNodeAttrConstValueProps,
  emits: ['change'],
  setup(props, { emit }) {
    const designStore = useComDesignStoreWithOut()

    const curConstEle = ref<any>(null)
    const curVisible = ref<boolean>(false)

    const curConstValue = ref<any>('')
    const curComVarName = ref<string>('')
    const curComParamName = ref<string>('')
    const curConstEleProps = ref<Record<string, any>>({})
    const curConstEleEmits = ref<Record<string, Function>>({})

    const curJSExpression = ref<BwJsExtndInfoModel>({})

    const curConstEleBindProps = computed(() => {
      const attrInfo = props.attrInfo ?? ({} as BwCurNodeAttrInfoModel)

      const options = unref(curConstEleProps)
      const com = attrInfo.constValueSetCom
      switch (com) {
        case BwComPropSetConstValueComEnum.input:
        case BwComPropSetConstValueComEnum.number:
        case BwComPropSetConstValueComEnum.select: {
          options.value = unref(curConstValue)
          break
        }
        case BwComPropSetConstValueComEnum.textarea: {
          const curValue = unref(curConstValue) ?? ''

          options.value =
            typeof curValue === 'string' ? curValue : JSON.stringify(curValue)
          break
        }
        case BwComPropSetConstValueComEnum.colSpan: {
          options.title = attrInfo.name
          options.value = unref(curConstValue)
          break
        }
        case BwComPropSetConstValueComEnum.switch: {
          options.checked = unref(curConstValue)
          break
        }
        case BwComPropSetConstValueComEnum.date: {
          options.value = unref(curConstValue)
        }
        case BwComPropSetConstValueComEnum.dateRange: {
          options.value = unref(curConstValue)
          break
        }
        case BwComPropSetConstValueComEnum.time: {
          options.value = unref(curConstValue)
          break
        }
        case BwComPropSetConstValueComEnum.color: {
          options.value = unref(curConstValue)
          break
        }
        case BwComPropSetConstValueComEnum.dataObjSelect: {
          options.value = unref(curConstValue)
          break
        }
        case BwComPropSetConstValueComEnum.dataObjField: {
          options.value = unref(curConstValue)
          options.dataObjId = props.attrData?.dataSourceDataObj?.constValue
          break
        }
        case BwComPropSetConstValueComEnum.tableColumnConfig: {
          options.value = unref(curConstValue)
          options.dataObjId = props.attrData?.dataSourceDataObj?.constValue
          break
        }
      }

      return options
    })

    /** 当前自定义组件外放属性列表 */
    const curCurtomComPropList = computed(() => {
      const list: Array<Record<string, string>> = []
      const designInfo = designStore.curDesignInfo
      const comProps = designInfo?.comProps

      if (Array.isArray(comProps) && comProps.length) {
        comProps.forEach((item) => {
          list.push({ label: item.name ?? '', value: item.key })
        })
      }
      return list
    })

    /** 初始化常量值配置组件 */
    const initConstEle = (com?: BwComPropSetConstValueComEnum) => {
      switch (com) {
        case BwComPropSetConstValueComEnum.input: {
          curConstEle.value = 'AInput'
          break
        }
        case BwComPropSetConstValueComEnum.number: {
          curConstEle.value = 'AInputNumber'
          break
        }
        case BwComPropSetConstValueComEnum.switch: {
          curConstEle.value = 'ASwitch'
          break
        }
        case BwComPropSetConstValueComEnum.select: {
          curConstEle.value = 'ASelect'
          break
        }
        case BwComPropSetConstValueComEnum.textarea: {
          curConstEle.value = 'ATextarea'
          break
        }
        case BwComPropSetConstValueComEnum.colSpan: {
          curConstEle.value = markRaw(BwColSpan)
          break
        }
        case BwComPropSetConstValueComEnum.date: {
          curConstEle.value = 'ADatePicker'
          break
        }
        case BwComPropSetConstValueComEnum.dateRange: {
          curConstEle.value = 'ARangePicker'
          break
        }
        case BwComPropSetConstValueComEnum.time: {
          curConstEle.value = 'ATimePicker'
          break
        }

        default: {
          curConstEle.value = 'ATextarea'
          break
        }
      }
    }

    /** 初始化常量值配置组件事件 */
    const initConstEleEmits = (com?: BwComPropSetConstValueComEnum) => {
      const emits: Record<string, Function> = {}
      switch (com) {
        case BwComPropSetConstValueComEnum.input:
        case BwComPropSetConstValueComEnum.textarea: {
          emits['update:value'] = (value) => {
            curConstValue.value = value
            onChangeAttrValue(value)
          }
          break
        }
        case BwComPropSetConstValueComEnum.number: {
          emits['update:value'] = (value) => {
            const curValue = [undefined, null].includes(value)
              ? 'null'
              : value.toString()

            curConstValue.value = value
            onChangeAttrValue(curValue)
          }
          break
        }
        case BwComPropSetConstValueComEnum.select: {
          emits['update:value'] = (value) => {
            const curValue = Array.isArray(value)
              ? JSON.stringify(value)
              : value.toString()

            curConstValue.value = value
            onChangeAttrValue(curValue)
          }
          break
        }
        case BwComPropSetConstValueComEnum.switch: {
          emits['update:checked'] = (value) => {
            const curValue = [undefined, null].includes(value)
              ? 'null'
              : value.toString()

            curConstValue.value = value
            onChangeAttrValue(curValue)
          }
          break
        }
        case BwComPropSetConstValueComEnum.colSpan: {
          emits['update:value'] = (value) => {
            const curValue = [undefined, null].includes(value)
              ? 'null'
              : JSON.stringify(value)

            curConstValue.value = value
            onChangeAttrValue(curValue)
          }
          break
        }
        case BwComPropSetConstValueComEnum.date: {
          emits['update:value'] = (value) => {
            curConstValue.value = value
            onChangeAttrValue(value)
          }
          break
        }
        case BwComPropSetConstValueComEnum.dateRange: {
          emits['update:value'] = (value) => {
            curConstValue.value = value
            onChangeAttrValue(value)
          }
          break
        }
        case BwComPropSetConstValueComEnum.time: {
          emits['update:value'] = (value) => {
            curConstValue.value = value
            onChangeAttrValue(value)
          }
          break
        }
        case BwComPropSetConstValueComEnum.color: {
          emits['update:value'] = (value) => {
            curConstValue.value = value
            onChangeAttrValue(value)
          }
          break
        }
        case BwComPropSetConstValueComEnum.dataObjSelect: {
          emits['update:value'] = (value) => {
            curConstValue.value = value
            onChangeAttrValue(value)
          }
          break
        }
        case BwComPropSetConstValueComEnum.dataObjField: {
          emits['update:value'] = (value) => {
            curConstValue.value = value
            onChangeAttrValue(value)
          }
          break
        }
        case BwComPropSetConstValueComEnum.tableColumnConfig: {
          emits['update:value'] = (value) => {
            curConstValue.value = value
            onChangeAttrValue(value)
          }
          break
        }
      }
      curConstEleEmits.value = emits
    }

    /** 初始化常量值配置组件属性 */
    const initConstEleProps = (
      com?: BwComPropSetConstValueComEnum,
      props?: string
    ) => {
      curConstEleProps.value = {}
      try {
        const options = props ? JSON.parse(props) : {}
        switch (com) {
          case BwComPropSetConstValueComEnum.number: {
            options.style = `width: 100%`
            break
          }
          case BwComPropSetConstValueComEnum.select: {
            options.style = `width: 100%`
            options.value = unref(curConstValue)
            break
          }
          case BwComPropSetConstValueComEnum.switch: {
            options.checked = unref(curConstValue)
            break
          }
        }
        curConstEleProps.value = options
      } catch (error) {
        console.error(error)
      }
    }

    const toDataTypeValue = (
      value: string,
      dataType?: BwCustomComPropDataTypeEnum | BwCustomComNodeAttrDataTypeEnum
    ) => {
      switch (dataType) {
        case BwCustomComNodeAttrDataTypeEnum.string:
        case BwCustomComPropDataTypeEnum.string: {
          return value
        }
        case BwCustomComNodeAttrDataTypeEnum.boolean:
        case BwCustomComPropDataTypeEnum.boolean: {
          return ['true', true].includes(value) ? true : false
        }
        case BwCustomComNodeAttrDataTypeEnum.number:
        case BwCustomComPropDataTypeEnum.number: {
          return ['null', 'undefined', ''].includes(value)
            ? undefined
            : Number(value)
        }
        case BwCustomComNodeAttrDataTypeEnum.array:
        case BwCustomComPropDataTypeEnum.array: {
          if (Array.isArray(value)) {
            return value
          }
        }
        case BwCustomComNodeAttrDataTypeEnum.object:
        case BwCustomComPropDataTypeEnum.object: {
          try {
            return value ? JSON.parse(value) : undefined
          } catch (error) {
            console.error(error)
            return undefined
          }
        }
        default: {
          return undefined
        }
      }
    }

    /** 初始化属性值 */
    const initAttrValue = (
      attrInfo?: BwCurNodeAttrInfoModel,
      attrData?: Record<string, BwCustomComNodeAttrModel>
    ) => {
      if (attrInfo && attrData) {
        const name = attrInfo.key
        const curItem = attrData[name ?? '']

        if (curItem) {
          const valueFrom = curItem.valueFromType
          switch (valueFrom) {
            case BwCustomComNodeAttrFromTypeEnum.constValue: {
              if (curItem.constValue) {
                const dataType = curItem.valueDataType
                curConstValue.value = toDataTypeValue(
                  curItem.constValue,
                  dataType ?? undefined
                )
              } else {
                const deftValue = attrInfo.defaultValue ?? ''
                const dataType = attrInfo.defaultValueDataType
                curConstValue.value = toDataTypeValue(
                  deftValue,
                  dataType ?? undefined
                )
              }
              break
            }
            case BwCustomComNodeAttrFromTypeEnum.comVar: {
              curComVarName.value = curItem.comVarName ?? ''
            }
            case BwCustomComNodeAttrFromTypeEnum.comProps: {
              curComParamName.value = curItem.comPropsName ?? ''
            }
            case BwCustomComNodeAttrFromTypeEnum.JSExpression: {
              curJSExpression.value = {
                logic: curItem.jsExpBodyLogic ?? undefined,
                params: curItem.jsExpParams ?? undefined,
              }
            }
          }
        } else {
          const deftValue = attrInfo.defaultValue ?? ''
          const dataType = attrInfo.defaultValueDataType

          curComVarName.value = ''
          curComParamName.value = ''
          curConstValue.value = toDataTypeValue(
            deftValue,
            dataType ?? undefined
          )
        }
      }
    }

    /** 更新JS表达式 */
    const onChangeJSExpression = (data: BwJsExtndInfoModel) => {
      const curValue: Record<string, any> = {
        jsExpParams: data.params,
        jsExpBodyLogic: data.logic,
      }

      onChangeAttrValue(curValue)
    }

    /** 修改组件属性值 */
    const onChangeAttrValue = (value: any) => {
      const curAttrName = props?.attrInfo?.key ?? ''
      emit('change', curAttrName, value)
    }

    watch(
      () => props.attrInfo,
      (newVal?: BwCurNodeAttrInfoModel) => {
        if (newVal) {
          const com = newVal.constValueSetCom
          const comProps = newVal.constValueSetComProps

          initConstEle(com)
          initConstEleEmits(com)
          initAttrValue(newVal, props.attrData)
          initConstEleProps(com, comProps ?? undefined)
        } else {
          curConstEle.value = null
          curConstValue.value = ''
          curComVarName.value = ''
          curComParamName.value = ''
          curConstEleEmits.value = {}
        }
      },
      { deep: true, immediate: true }
    )

    watch(
      () => props.attrData,
      (newVal?: Record<string, BwCustomComNodeAttrModel>) => {
        if (newVal) {
          nextTick(() => {
            initAttrValue(props.attrInfo, newVal)
          })
        }
      },
      { deep: true, immediate: false }
    )

    return {
      curVisible,

      curConstEle,
      curComVarName,
      curComParamName,
      curJSExpression,
      curConstEleEmits,

      curCurtomComPropList,
      curConstEleBindProps,
      BwCustomComNodeAttrFromTypeEnum: BwCustomComNodeAttrFromTypeEnum,

      onChangeAttrValue,
      onChangeJSExpression,
    }
  },
})
</script>

<style lang="less" scoped></style>
